﻿using System;
using System.Collections.Generic;
using System.Text;
using Ivi.Driver.Interop;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using Ivi.ConfigServer.Interop;
using System.Globalization;
using System.Reflection;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;

namespace AIRO.Devices.Solenoid
{
    [Guid("DDF29F44-4B9D-4e39-B00F-AF77C044AD45")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("MyDevices.Solenoid.AMI420")]
    public class AMI420 : BasicIviDriverVisa, Ivi.Driver.Interop.IIviDriver, IIviDriverIdentity, IIviComponentIdentity, IIviDriverOperation, IIviDriverUtility, ISolenoid
    {
        private const double maxCurrentLimit = 200;
        private const double maxVoltageLimit = 12;
        
        private double coilConst;
        //private IAsyncResult asyncHandle = null;
        private SolenoidState currentState;
        private System.ComponentModel.BackgroundWorker backgroundWorker;
        private bool fieldSettled = false;
        double _accuracy;
        private double currentLimit;
        private double voltageLimit;

        public AMI420():base()
        {            
            backgroundWorker = new BackgroundWorker();
            InitializeBackgoundWorker();
            _description = "IVI Custom Driver for AMI MODEL 420 POWER SUPPLY PROGRAMMER";
            _supportedInstrumentModels = "AMI420";
            _identifier = "AMI420";
            _vendor = "LNEP ISSP(RAS)";
            _instrumentManufacturer = "American Magnetics, Inc";
        }

        [FlagsAttribute]
        private enum StandardEvents : byte
        {
            OperationComplete = 1,
            QueryError = 4,
            DeviceError = 8,
            ExecutionError = 16,
            CommandError = 32,
            PowerOn = 128,
            Error = 4 + 8 + 16 + 32
        }

        [FlagsAttribute]
        private enum StatusBits : byte
        {
            QuenchCondition = 4,
            SerialOutputBuffer = 8,
            IEEE488OutputBuffer = 16,
            StandardEventRegister = 32,
            SummaryBit = 64
        }

        #region Properties

        public double Accuracy
        {
            get
            {
                return _accuracy;
            }
            set
            {
                if (value > 0)
                {
                    _accuracy = value;
                }
            }
        }

        public bool Quench
        {
            get
            {
                string cmd = "QUench?;";
                return System.Convert.ToBoolean(Query(cmd));
            }
            set
            {
                string val;
                if (value)
                {
                    val = "1";
                }
                else
                {
                    val = "0";
                }
                string cmd = String.Format("QUench {0};", val);
                SendCommand(cmd);

            }
        }

        public SolenoidState State
        {
            get
            {
                if (_initialized)
                {
                    return getState();
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                    //return SolenoidState.Error;
                }
            }
        }

        public double MagnetField
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "FIELD:MAGnet?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }

        }

        public double MagnetCurrent
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "CURRent:MAGnet?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }

        }

        public double MagnetVoltage
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "VOLTage:MAGnet?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }

        }

        public double SupplyVoltage
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "VOLTage:SUPPly?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }

        }

        public double RampRateField
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "RAMP:RATE:FIELD?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format(numericFormatProvider, "CONFigure:RAMP:RATE:FIELD {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double RampRateCurrent
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "RAMP:RATE:CURRent?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format(numericFormatProvider, "CONFigure:RAMP:RATE:CURRent {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public bool RampRateUnits
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "RAMP:RATE:UNITS?;";
                    return System.Convert.ToBoolean(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                setRampRateUnits(value);
            }
        }

        public bool FieldUnits
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "FIELD:UNITS?;";
                    return System.Convert.ToBoolean(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                setFieldUnits(value);
            }
        }

        public bool Absorber
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "ABsorber?;";
                    return System.Convert.ToBoolean(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                setAbsorber(value);
            }
        }

        public byte StandardEventEnableRegister
        {
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format("*ESE {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            get
            {
                if (_initialized)
                {
                    string cmd = "*ESE?;";
                    return System.Convert.ToByte(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double CurrentLimit
        {

            get
            {
                if (_initialized)
                {
                    string cmd = "CURRent:LIMit?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    double currentLimit;
                    if (value <= maxCurrentLimit)
                        currentLimit = value;
                    else
                        currentLimit = maxCurrentLimit;
                    string cmd = String.Format(numericFormatProvider, "CONFigure:CURRent:LIMit {0};", currentLimit);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double VoltageLimit
        {

            get
            {
                if (_initialized)
                {
                    string cmd = "VOLTage:LIMit?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {

                    if (value <= maxVoltageLimit)
                        voltageLimit = value;
                    else
                        voltageLimit = maxVoltageLimit;
                    string cmd = String.Format(numericFormatProvider, "CONFigure:CURRent:LIMit {0};", voltageLimit);
                    //string cmd = String.Format(numericFormatProvider, "CONFigure:VOLTage:LIMit {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double ProgrammedCurrent
        {

            get
            {
                if (_initialized)
                {

                    string cmd = "CURRent:PROGram?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    if (Math.Abs(value) <= currentLimit)
                    {
                        string cmd = String.Format(numericFormatProvider, "CONFigure:CURRent:PROGram {0};", value);
                        SendCommand(cmd);
                    }
                    else
                        throw new ArgumentException("Out of Range");
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double ProgrammedField
        {

            get
            {
                if (_initialized)
                {
                    string cmd = "FIELD:PROGram?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    if (Math.Abs(value) <= coilConst * currentLimit)
                    {
                        string cmd = String.Format(numericFormatProvider, "CONFigure:FIELD:PROGram {0};", value);
                        SendCommand(cmd);
                    }
                    else
                        throw new ArgumentException("Out of range");
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double Stability
        {

            get
            {
                if (_initialized)
                {
                    string cmd = "STABility?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format(numericFormatProvider, "CONFigure:STABility {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public double CoilConstant
        {

            get
            {
                if (_initialized)
                {
                    string cmd = "COILconst?;";
                    return System.Convert.ToDouble(Query(cmd), numericFormatProvider);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format(numericFormatProvider, "CONFigure:COILconst {0};", value);
                    SendCommand(cmd);
                    coilConst = value;
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public byte StandardEventRegister
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "*ESR?;";
                    string res = Query(cmd);
                    return System.Convert.ToByte(res);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public byte StatusByteRegister
        {
            get
            {
                if (_initialized)
                {
                    string cmd = "*STB?;";
                    return System.Convert.ToByte(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        public byte StatusByteEnableRegister
        {
            set
            {
                if (_initialized)
                {
                    string cmd = String.Format("*SRE {0};", value);
                    SendCommand(cmd);
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
            get
            {
                if (_initialized)
                {
                    string cmd = "*SRE?;";
                    return System.Convert.ToByte(Query(cmd));
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    throw new Exception("Driver is not initialized");
                }
            }
        }

        #endregion

        #region Public methods

        public void Pause()
        {
            if (_initialized)
            {
                string cmd = "PAUSE" + "; " + "*OPC?;";
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }

                CheckState();
                //BeginQuery(cmd,new AsyncCallback(OnOperationComplete));
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void BeginRamp()
        {
            if (_initialized)
            {
                fieldSettled = false;
                if (currentState != SolenoidState.Running)
                {
                    currentState = SolenoidState.Running;
                    OnStateChangedEvent(new StateChangedEventArgs(SolenoidState.Running));
                }
                string cmd = "RAMP" + "; " + "*OPC?;";
                /*
                if (_waitForSettling)
                {
                    
                    backgroundWorker.RunWorkerAsync(cmd);
                    
                }
                else
                {
                    BeginQuery(cmd, new AsyncCallback(OnOperationComplete));
                }
                 * */
                backgroundWorker.RunWorkerAsync(cmd);

            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void Up()
        {
            if (_initialized)
            {
                string cmd = "UP" + "; " + "*OPC?;";
                // BeginQuery(cmd, new AsyncCallback(OnOperationComplete));
                if (currentState != SolenoidState.Running)
                {
                    currentState = SolenoidState.Running;
                    OnStateChangedEvent(new StateChangedEventArgs(SolenoidState.Running));
                }
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }

                CheckState();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void Down()
        {
            if (_initialized)
            {
                string cmd = "DOWN" + "; " + "*OPC?;";
                //BeginQuery(cmd, new AsyncCallback(OnOperationComplete));
                if (currentState != SolenoidState.Running)
                {
                    currentState = SolenoidState.Running;
                    OnStateChangedEvent(new StateChangedEventArgs(SolenoidState.Running));
                }
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }

                CheckState();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }
        
        private string QueryAndWaitForSettling(string cmd, BackgroundWorker worker, DoWorkEventArgs e)
        {
            //string cmd = (string)objCmd;

            string res = Query(cmd);

            if (res != "1")
                return res;
            else
            {
                double targetField;
                double field;
                do
                {
                    field = MagnetField;
                    targetField = ProgrammedField;
                    //worker.ReportProgress(0, field);
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        return res;
                    }

                } while (Math.Abs(field - targetField) > _accuracy);
                fieldSettled = true;
                return res;
            }


        }

        /*

        private void BeginQuery(string cmd, AsyncCallback callback)
        {
            string textToWrite = ReplaceCommonEscapeSequences(cmd);
            lock (mbSession)
            {
                mbSession.Write(textToWrite);
                asyncHandle = mbSession.BeginRead(mbSession.DefaultBufferSize, callback, null);
            }
        }
         * */

        /*
        private void OnOperationComplete(IAsyncResult result)
        {
            string responseString = mbSession.EndReadString(result);
            string res = TrimEnd(responseString);
            //lastIOStatusTextBox.Text = mbSession.LastStatus.ToString();
            //elementsTransferredTextBox.Text = responseString.Length.ToString();

            if (res != "1")
            {
                SolenoidState state = SolenoidState.Error;
                OnStateChangedEvent(new StateChangedEventArgs(state));
                currentState = state;
                return;
            }

            CheckState();

        }
         * */       
              
        public void ConfigureRampField(double field, double rate)
        {
            if (_initialized)
            {
                if (Math.Abs(field) <= coilConst * currentLimit)
                {
                    string cmd = String.Format(numericFormatProvider, "CONFigure:RAMP:FIELD {0} {1};", field, rate);
                    SendCommand(cmd);
                }
                else
                    throw new ArgumentException("Out of range");

            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void Clear()
        {
            if (_initialized)
            {
                string cmd = "*CLS; *OPC?;";
                Query(cmd);
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void BeginGotoField(double field)
        {
            ProgrammedField = field;
            BeginRamp();
        }

        //double defaultRate;
        /*
        public void GoTo(double field)
        {
            return GoTo(field, defaultRate);
        }
         * */
        public void GoToZero()
        {
            if (_initialized)
            {
                string cmd = "ZERO" + "; " + "*OPC?;";
                //BeginQuery(cmd, new AsyncCallback(OnOperationComplete));
                if (currentState != SolenoidState.Running)
                {
                    currentState = SolenoidState.Running;
                    OnStateChangedEvent(new StateChangedEventArgs(SolenoidState.Running));
                }
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }
                CheckState();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }

        public void Cancel()
        {
            if (_initialized)
            {
                if (backgroundWorker.IsBusy)
                    backgroundWorker.CancelAsync();
                string cmd = "PAUSE; *OPC?;";
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }
                CheckState();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }

        }

        #endregion

        protected virtual void OnStateChangedEvent(StateChangedEventArgs e)
        {
            EventHandler<StateChangedEventArgs> handler = StateChangedEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnFieldSetEvent(FieldSetEventArgs e)
        {
            EventHandler<FieldSetEventArgs> handler = FieldSetEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected virtual void OnProgressEvent(ProgressEventArgs e)
        {
            EventHandler<ProgressEventArgs> handler = ProgressEvent;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #region Private methods

        private void CheckState()
        {
            SolenoidState state = State;

            if ((StandardEventRegister & (byte)StandardEvents.Error) != 0)
            {
                state = SolenoidState.Error;
                OnStateChangedEvent(new StateChangedEventArgs(state));
                currentState = state;
                return;
            }
            if (currentState != state)
            {
                OnStateChangedEvent(new StateChangedEventArgs(state));
                /*
                if ((currentState == SolenoidState.Running) & (state == SolenoidState.Idle))
                    OnFieldSetEvent(new FieldSetEventArgs(Field));
                 * */

                currentState = state;
            }
            if (fieldSettled)
            {
                OnFieldSetEvent(new FieldSetEventArgs(MagnetField));
                fieldSettled = false;
            }
        }

        /*
        bool _waitForSettling;
        public bool WaitForSettling
        {
            get
            {
                return _waitForSettling;
            }
            set
            {
                _waitForSettling = value;
            }
        }
        */

        // Set up the BackgroundWorker object by 
        // attaching event handlers. 
        private void InitializeBackgoundWorker()
        {
            backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
            backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
            backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            if (e.Error == null)
                if (!e.Cancelled)
                {
                    if ((string)e.Result == "1")
                    {
                        CheckState();
                        return;
                    }
                }
                else
                {
                    CheckState();
                    return;
                }


            SolenoidState state = SolenoidState.Error;
            OnStateChangedEvent(new StateChangedEventArgs(state));
            currentState = state;
            return;

        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            OnProgressEvent(new ProgressEventArgs((double)e.UserState));
            CheckState();
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = (BackgroundWorker)sender;
            e.Result = QueryAndWaitForSettling((string)e.Argument, worker, e);
            //throw new NotImplementedException();
        }

        private SolenoidState getState()
        {
            string cmd = "STATE?;";
            string state = Query(cmd);
            switch (state)
            {
                case "1":
                case "4":
                case "5":
                case "6":
                    return SolenoidState.Running;
                case "2":
                case "9":
                    return SolenoidState.Idle;

                case "3":
                    return SolenoidState.Paused;

                case "7":
                    return SolenoidState.QuenchDetected;

                case "8":
                    return SolenoidState.HeatingPersistentSwitch;

                default:
                    return SolenoidState.Error;

            }
        }

        private void setRampRateUnits(bool value)
        {
            string val;
            if (value)
            {
                val = "1";
            }
            else
            {
                val = "0";
            }
            string cmd = String.Format("CONFigure:RAMP:RATE:UNITS {0}; *OPC?;", val);
            Query(cmd);
        }

        private void setFieldUnits(bool value)
        {
            string val;
            if (value)
            {
                val = "1";
            }
            else
            {
                val = "0";
            }
            string cmd = String.Format("CONFigure:FIELD:UNITS {0}; *OPC?;", val);
            Query(cmd);
        }


        private void setAbsorber(bool value)
        {
            string val;
            if (value)
            {
                val = "1";
            }
            else
            {
                val = "0";
            }
            string cmd = String.Format("CONFigure:ABsorber {0}; *OPC?;", val);
            Query(cmd);
        }

        #endregion    

        public event EventHandler<StateChangedEventArgs> StateChangedEvent;

        public event EventHandler<FieldSetEventArgs> FieldSetEvent;

        public event EventHandler<ProgressEventArgs> ProgressEvent;

        
        #region IIviDriver Members

        public override void Close()
        {
            if (_initialized)
            {
                string cmd = "PAUSE; *OPC?;";
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }
                CheckState();
                /*
                if (mbSession != null)
                {
                   mbSession.Dispose();
                } 
                 * */
                //mbSession.Dispose();
                instrument.IO.Close();
                _initialized = false;
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                throw new Exception("Driver is not initialized");
            }
        }      
        
        public void Initialize(string ResourceName, bool IdQuery, bool Reset, string OptionString)
        {
            if (!_initialized)
            {//string ioResourceDescriptor;
                //resourceName = ResourceName;
                _rangeCheck = true;
                _cache = true;
                _queryInstrumentStatus = false;
                _simulate = false;
                _driverSetup = "";
                _recordCoercions = false;
                _interchangeCheck = false;
                _accuracy = 0.0001;

                InitVisaMessageBasedSession(ResourceName);
                ParseOptionString(OptionString);
                if (Reset)
                {
                    this.Reset();
                }
                string cmd = "*CLS; *OPC?;";
                Query(cmd);
                currentState = getState();
                /*
                byte statusByteEnableRegister = (byte)StatusBits.StandardEventRegister;
                cmd = "*SRE "+statusByteEnableRegister.ToString();
                Query(cmd);
                 * */
                byte standardEventEnableRegister = (byte)(StandardEvents.CommandError | StandardEvents.DeviceError | StandardEvents.ExecutionError | StandardEvents.OperationComplete | StandardEvents.QueryError);
                cmd = String.Format("*ESE {0}; *OPC?;", standardEventEnableRegister.ToString());
                Query(cmd);
                _initialized = true;
                //mbSession.ServiceRequest += new MessageBasedSessionEventHandler(mbSession_ServiceRequest);

            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_ALREADY_INITIALIZED));
            }

        }

        protected override void ConfigureInitialSettings(IIviStructure confInitialSettings)
        {
            string cmd;
            foreach (IIviDataComponent dataComp in confInitialSettings.DataComponents)
            {
                //System.Diagnostics.Debug.WriteLine(dataComp.Name);
                string name = dataComp.Name;
                switch (name.ToLower())
                {
                    case "accuracy":
                        _accuracy = ((IIviReal)dataComp).Value;
                        break;
                    /*
                case "waitforsettling":
                    _waitForSettling = ((IIviBoolean)dataComp).Value;
                    break;
                     * */
                    case "coilconstant":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            coilConst = value;
                            cmd = String.Format(numericFormatProvider, "CONFigure:COILconst {0}; *OPC?;", value);
                            Query(cmd);

                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "voltagelimit":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            //double limit;
                            if (value <= maxVoltageLimit)
                                voltageLimit = value;
                            else
                                voltageLimit = maxVoltageLimit;
                            cmd = String.Format(numericFormatProvider, "CONFigure:VOLTage:LIMit {0}; *OPC?;", voltageLimit);

                            Query(cmd);
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "fieldunits":
                        try
                        {
                            bool value = ((IIviBoolean)dataComp).Value;
                            setFieldUnits(value);
                            /*
                            cmd = "CONFigure:FIELD:UNITS " + value;
                            SendCommand(cmd);
                             * */
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "ramprateunits":
                        try
                        {
                            bool value = ((IIviBoolean)dataComp).Value;
                            setRampRateUnits(value);
                            /*
                            cmd = "CONFigure:RAMP:RATE:UNITS " + value;
                            SendCommand(cmd);
                             * */
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "absorber":
                        try
                        {
                            bool value = ((IIviBoolean)dataComp).Value;
                            setAbsorber(value);
                            /*
                            cmd = "CONFigure:ABsorber " + value;
                            SendCommand(cmd);
                             * */


                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "stability":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            cmd = String.Format(numericFormatProvider, "CONFigure:STABility {0}; *OPC?;", value);
                            Query(cmd);
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "currentlimit":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            //double limit;
                            if (value <= maxCurrentLimit)
                                currentLimit = value;
                            else
                                currentLimit = maxCurrentLimit;
                            cmd = String.Format(numericFormatProvider, "CONFigure:CURRent:LIMit {0}; *OPC?;", currentLimit);
                            Query(cmd);
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "rampratecurrent":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            cmd = String.Format(numericFormatProvider, "CONFigure:RAMP:RATE:CURRent {0}; *OPC?;", value);
                            Query(cmd);
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "rampratefield":
                        try
                        {
                            double value = ((IIviReal)dataComp).Value;
                            cmd = String.Format(numericFormatProvider, "CONFigure:RAMP:RATE:FIELD {0}; *OPC?;", value);
                            Query(cmd);
                            /*
                            int errCode=0;
                            string errMsg="";
                            ErrorQuery(ref errCode, ref errMsg);
                            MessageBox.Show(errMsg);
                             * */
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    default:
                        iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_BAD_OPTION_NAME));
                        break;
                }


            }

        }

        /*
        void mbSession_ServiceRequest(object sender, MessageBasedSessionEventArgs e)
        {
            SolenoidState state = State ;

            if (currState != state)
            {
                OnStateChangedEvent(new StateChangedEventArgs(state));
                if ((currState == SolenoidState.Running) & (state == SolenoidState.Idle))
                    OnFieldSetEvent(new FieldSetEventArgs(Field));               
                currState = state;
            }

            if ((StandardEventRegister & (byte)StandardEvents.Error) !=0)
            {
                state = SolenoidState.Error;
                OnStateChangedEvent(new StateChangedEventArgs(state));
                currState = state;
            }
            

           
        }
         * */      

        #endregion

        #region IIviDriverUtility Members

        public void Disable()
        {
            if (_initialized)
            {
                GoToZero();
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }
                
        public override void ErrorQuery(ref int ErrorCode, ref string ErrorMessage)
        {
            /*
            if (IviDriverErrorQueue.Count > 0)
            {
                Error err = IviDriverErrorQueue.Dequeue();
                ErrorCode = err.ErrorCode;
                ErrorMessage = err.ErrorMessage;
            }
            else
            {

            }
             * */
            string cmd = "SYSTem:ERRor?;";
            string reply = Query(cmd);
            const string errorStringPattern = "((?<ErrorCode>0),\\s*\x22(?<ErrorMessage>No errors)\x22)|((?<ErrorCode>-\\d{3}),\\s*\x22(?<ErrorMessage>[^;,]*)\x22)";
            Regex errorStringRegex = new Regex(errorStringPattern, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match m = errorStringRegex.Match(reply);
            if (m.Success)
            {
                ErrorCode = System.Convert.ToInt32(m.Groups["ErrorCode"].Value);
                ErrorMessage = m.Groups["ErrorMessage"].Value;
            }
            else
            {
                throw new Exception();
            }

        }
        
        public override void Reset()
        {
            if (_initialized)
            {
                //mdrCh.Wind(0);
                GoToZero();
                string cmd = "*RST; *OPC?;";
                string res = Query(cmd);
                if (res != "1")
                {
                    SolenoidState state = SolenoidState.Error;
                    OnStateChangedEvent(new StateChangedEventArgs(state));
                    currentState = state;
                    return;
                }
                CheckState();
                interchangeWarningQueue.Enqueue("User called the Reset function");
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));

            }
        }

        public override void ResetWithDefaults()
        {
            if (_initialized)
            {
                Reset();
                /*
                byte statusByteEnableRegister = (byte)StatusBits.StandardEventRegister;
                string cmd = "*SRE " + statusByteEnableRegister.ToString();
                Query(cmd);
                 * */
                byte standardEventEnableRegister = (byte)(StandardEvents.CommandError | StandardEvents.DeviceError | StandardEvents.ExecutionError | StandardEvents.OperationComplete | StandardEvents.QueryError);
                string cmd = String.Format("*ESE {0}; *OPC?;", standardEventEnableRegister.ToString());
                Query(cmd);

            }

            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        public override void SelfTest(ref int TestResult, ref string TestMessage)
        {
            string cmd = "*TST?;";
            string res = Query(cmd);
            if (res == "1")
            {
                TestResult = 0;
                TestMessage = "Self test passed";
            }
            //IviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.S_IVI_NSUP_SELF_TEST));
            //throw new NotImplementedException();
        }

        #endregion
        
        
    }
}
